﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using System.IO;


namespace SkyBase
{

    /*
     *  TO DO: CLEAN UP LOAD CONTENT SO NOTHING IS DONE MANUALLY AND REMOVE "LOADTEXTURE" AND REPLACE IT WITH LOADFILE<>
     * 
     * */
    /// <summary>
    /// Stores textures and other static data.
    /// </summary>
    public static class Storage
    {
        //All files should be accessed through the appropriate methods.

        //Load textures here
        private static Dictionary<string, Texture2D> textures = new Dictionary<string, Texture2D>();
        //Ditto for fonts
        private static Dictionary<string, SpriteFont> fonts = new Dictionary<string, SpriteFont>();

        //Animation map for the player. Would abstract, but is unnecessary for the scope of the project. C'est la vie.
        private static Dictionary<direction, List<Texture2D>> animationMap = new Dictionary<direction,List<Texture2D>>();
        private static Dictionary<direction, List<Texture2D>> robotAnimMap = new Dictionary<direction, List<Texture2D>>();
        public static ContentManager content;

        /// <summary>
        /// Automatically adds all textures in Content/Textures to the library
        /// </summary>
        public static void loadContent()
        {
            Debugger.debug("Loading storage content. (Textures, etc.)");
            DirectoryInfo dir = new DirectoryInfo(content.RootDirectory + "/Textures");
            IEnumerable<FileInfo> files = dir.GetFiles("*.*");



            //Load primary textures
            foreach (FileInfo f in files)
            {
                    if (f.Extension == ".xnb")
                    {
                        Debugger.writeLine("Found texture file in Content, proceeding to add [" + f.Name + "]");
                        Debugger.writeLine("Loading: <" + dir.Name + "/" + Path.GetFileNameWithoutExtension(f.Name) + ">");
                        loadTexture(dir.Name + "/" + Path.GetFileNameWithoutExtension(f.Name), Path.GetFileNameWithoutExtension(f.Name));
                    }

            }

            //Load animations for player
            //Yes, yes, this is all done horribly manually.
            //I AM NOT PROUD OF THIS, I'M JUST OUT OF TIME.
            Debugger.debug("Loading player animations");
            dir = new DirectoryInfo(content.RootDirectory + "/Textures/TextureMaps/Character");
            Debugger.writeLine("Entering directory " + dir.FullName);
            IEnumerable<DirectoryInfo> directories = dir.GetDirectories();
            List<Texture2D> frames;
            foreach (DirectoryInfo directory in directories)
            {
                Debugger.writeLine("Diving into subdirectory " + directory.Name);
                frames = new List<Texture2D>();
                files = directory.GetFiles("*.*");
                foreach (FileInfo f in files)
                {
                    if (f.Extension == ".xnb")
                    {
                        frames.Add(content.Load<Texture2D>("Textures/TextureMaps/Character/" + directory.Name + "/" + Path.GetFileNameWithoutExtension(f.Name)));
                    }
                }
                animationMap.Add(convertTextToDirection(directory.Name), frames);
                Debugger.writeLine("Added all textures in " + directory.Name);
            }

            Debugger.debug("Loading robot animations");
            dir = new DirectoryInfo(content.RootDirectory + "/Textures/TextureMaps/Robot");
            Debugger.writeLine("Entering directory "+dir.FullName);
            directories = dir.GetDirectories();
            foreach (DirectoryInfo directory in directories)
            {
                Debugger.debug("Diving into subdirectory " + directory.Name);
                frames = new List<Texture2D>();
                files = directory.GetFiles("*.*");
                foreach (FileInfo f in files)
                {
                    if (f.Extension == ".xnb")
                    {
                        frames.Add(content.Load<Texture2D>("Textures/TextureMaps/Robot/" + directory.Name + "/" + Path.GetFileNameWithoutExtension(f.Name)));
                    }
                }
                robotAnimMap.Add(convertTextToDirection(directory.Name), frames);
                Debugger.writeLine("Added all textures in " + directory.Name);
            }

            Debugger.enabled = true;
            Debugger.debug("Loading fonts");
            dir = new DirectoryInfo(content.RootDirectory + "/Fonts");
            Debugger.writeLine("Entering directory " + dir.FullName);
            //Load primary textures
            foreach(FileInfo f in dir.EnumerateFiles())
            {
                if (f.Extension == ".xnb")
                {
                    Debugger.writeLine("Found font file in Content, proceeding to add [" + f.Name + "]");
                    Debugger.writeLine("Loading: <" + dir.Name + "/" + Path.GetFileNameWithoutExtension(f.Name) + ">");
                    loadFont(dir.Name + "/" + Path.GetFileNameWithoutExtension(f.Name), Path.GetFileNameWithoutExtension(f.Name));
                }

            }




            Debugger.enabled = false;
            Debugger.debug("Finished loading storage content");
        }

        private static direction convertTextToDirection(string input)
        {
            switch (input)
            {
                case ("Back"):
                    return direction.TOP;
                case ("Front"):
                    return direction.BOTTOM;
                case ("Left"):
                    return direction.LEFT;
                case ("Right"):
                    return direction.RIGHT;
                case ("LeftBack"):
                    return direction.TOPLEFT;
                case ("LeftFront"):
                    return direction.BOTTOMLEFT;
                case ("RightBack"):
                    return direction.TOPRIGHT;
                case ("RightFront"):
                    return direction.BOTTOMRIGHT;
                default:
                    return direction.NONE;
            }
        }

        /// <summary>
        /// Load texture file at [location] and give it (optional) [name]
        /// If name isn't specified the file name will be used.
        /// </summary>
        /// <param name="location">The path of the texture to load (WITHOUT extension)</param>
        /// <param name="name">The name (key) of the texture to load.</param>
        public static void loadTexture(string location, string name = null)
        {
            Texture2D toAdd = Storage.content.Load<Texture2D>(location);
            if (name == null)
            {
                FileInfo f = new FileInfo(location);
                name = f.Name;
            }

            Debugger.writeLine("Added texture [" + name + "]");
            textures.Add(name, toAdd);


        }

        /// <summary>
        /// Load fonts
        /// </summary>
        /// <param name="location"></param>
        /// <param name="name"></param>
        public static void loadFont(string location, string name = null)
        {
            SpriteFont toAdd = Storage.content.Load<SpriteFont>(location);
            if (name == null)
            {
                FileInfo f = new FileInfo(location);
                name = f.Name;
            }

            Debugger.writeLine("Added font [" + name + "]");
            fonts.Add(name, toAdd);


        }


        public static List<Texture2D> getMap(string name, direction facing)
        {
            if (name != "player")
                return robotAnimMap[facing];
            else
                return animationMap[facing];
        }

        /// <summary>
        /// Removes a texture.
        /// </summary>
        /// <param name="name">The name (key) of the texture to remove.</param>
        public static void removeTexture(string name)
        {
            textures.Remove(name);
        }

        /// <summary>
        /// Get a texture from the library (for use in game).
        /// </summary>
        /// <param name="name">The name (key) of the texture to get.</param>
        /// <returns></returns>
        public static Texture2D getTexture(string name)
        {
            return textures[name];
        }

        /// <summary>
        /// Get a font from the library (for use in game).
        /// </summary>
        /// <param name="name">The font (key) of the texture to get.</param>
        /// <returns></returns>
        public static SpriteFont getFont(string name)
        {
            return fonts[name];
        }

        /// <summary>
        /// Every fucking goddamn programming language needs a method like this. Fuckers who don't implement this shit get the clamps.
        /// Also, uh, this takes a number and returns the nearest high or low.
        /// </summary>
        /// <param name="number">THE NUMBER TO FUCKING CLAMPS</param>
        /// <param name="high">THE NUMBER TO FUCKING CLAMPS TO</param>
        /// <param name="low">AN ALTERNATIVE SECONDARY (low) CLAMPS, IF NOT SPECIFIED USE THE OPPOSITE OF HIGH</param>
        /// <returns></returns>
        public static float clamp(float number, float high, float low = 0)
        {
            if (low == 0)
                low = high * -1;

            if (number.CompareTo(low) < 0) return low;
            else if (number.CompareTo(high) > 0) return high;
            else return number;

        }
    
    }
}
